import { Vec2, Vec3 } from "cc";
import { Loger } from "../loger/Loger";

/**
 * 线性同余随机数生成器
 */
export class RandomUtils {
    /**
     * 创建一个随机数生成器
     */
    public constructor(seed: number) {
        this.seed = seed;
        if (!this.seed && this.seed != 0) {
            this.seed = new Date().getTime();
        }
    }
    /**
     * 设置用于随机数生成器的种子，如果不设置则实际是取当前时间毫秒数
     */
    public seed: number;
    /**
     * 返回一个随机数，在0.0～1.0之间
     */
    public get value(): number {
        return this.range(0, 1);
    }
    /**
     * 返回半径为1的圆内的一个随机点
     */
    public get insideUnitCircle(): Vec2 {
        var randomAngle: number = this.range(0, 360);
        var randomDis: number = this.range(0, 1);
        var randomX: number = randomDis * Math.cos(randomAngle * Math.PI / 180);
        var randomY: number = randomDis * Math.sin(randomAngle * Math.PI / 180);
        return new Vec2(randomX, randomY);
    }
    /**
     * 返回半径为1的圆边的一个随机点
     */
    public get onUnitCircle(): Vec2 {
        var randomAngle: number = this.range(0, 360);
        var randomX: number = Math.cos(randomAngle * Math.PI / 180);
        var randomY: number = Math.sin(randomAngle * Math.PI / 180);
        return new Vec2(randomX, randomY);
    }
    /**
     * 返回一个在min和max之间的随机浮点数
     */
    public range(min: number, max: number): number {
        if (!this.seed && this.seed != 0) {
            this.seed = new Date().getTime();
        }
        max = max || 1;
        min = min || 0;
        this.seed = (this.seed * 9301 + 49297) % 233280;
        var rnd = this.seed / 233280.0;
        return min + rnd * (max - min);
    }
    /**
     * 设置用于随机数生成器的种子，如果不设置则实际是取当前时间毫秒数
     */
    public static seed: number;
    /**
     * 返回一个随机数，在0.0～1.0之间
     */
    public static get value(): number {
        return this.range(0, 1);
    }
    /**
     * 返回半径为1的圆内的一个随机点
     */
    public static get insideUnitCircle(): Vec3 {
        var randomAngle: number = this.range(0, 360);
        var randomDis: number = this.range();
        var randomX: number = randomDis * Math.cos(randomAngle * Math.PI / 180);
        var randomY: number = randomDis * Math.sin(randomAngle * Math.PI / 180);
        return new Vec3(randomX, randomY, 0);
    }
    /**
     * 返回半径为1的圆边的一个随机点
     */
    public static get onUnitCircle(): Vec3 {
        var randomAngle: number = this.range(0, 360);
        var randomX: number = Math.cos(randomAngle * Math.PI / 180);
        var randomY: number = Math.sin(randomAngle * Math.PI / 180);
        return new Vec3(randomX, randomY);
    }
    /**
     * 返回一个在min和max之间的随机浮点数
     */
    public static range(inMin: number = 0, inMax: number = 1): number {
        let max = inMax;
        let min = inMin;
        if (max < min) {
            max = inMin;
            min = inMax;
        } else if (max === min) {
            return max;
        }
        if (!this.seed && this.seed != 0) {
            this.seed = new Date().getTime();
        }
        max = max || 1;
        min = min || 0;
        this.seed = (this.seed * 9301 + 49297) % 233280;
        var rnd = this.seed / 233280.0;
        return min + rnd * (max - min);
    }
    /**
     * 返回一个在min和max之间的随机整数,包括最大值
     */
    public static rangeInt(inMin: number = 0, inMax: number = 1): number {
        let max = inMax;
        let min = inMin;
        if (max < min) {
            max = inMin;
            min = inMax;
        }
        var Range = max - min;
        var Rand = this.range(0, 1)
        return (min + Math.round(Rand * Range));
    }
    /**返回一个arr[0]到arr[1]之间的随机整数,包括最大值 */
    public static rangeIntByArr(arr: number[]): number {
        if (arr.length < 2) {
            return 0
        }
        return this.rangeInt(arr[0], arr[1])
    }
    /**返回一个arr[0]到arr[1]之间的随机数,包括最大值 */
    public static rangeByArr(arr: number[]): number {
        if (arr.length < 2) {
            return 0
        }
        return this.range(arr[0], arr[1])
    }
    /**从数组里随机一个元素 */
    public static rangeFromArr<T>(arr: Array<T>): T {
        let idx = this.rangeInt(0, arr.length - 1)
        return arr[idx]
    }
    /**根据权重数组的概率分布*/
    public static getIdxByWeight(arrWeight: Array<number>): number {
        let sum = 0;
        for (let i = 0; i < arrWeight.length; i++) {
            sum += arrWeight[i];
        }

        let random = this.range(0, sum)
        let sum_temp = 0
        for (let i = 0; i < arrWeight.length; i++) {
            sum_temp += arrWeight[i];
            if (random <= sum_temp) {
                return i;
            }
        }
        Loger.error("没随到");
        return 0;
    }

    public static getArrValueByWeight<T>(arrValue: Array<T>, arrWeight: Array<number>, count: number = 1): T[] {
        if (!count || count <= 1) {
            return [arrValue[this.getIdxByWeight(arrWeight)]];
        }
        if (arrValue.length !== arrWeight.length) {
            Loger.error("源数据和权重数据数量不等!!!!")
            if (arrWeight.length > arrValue.length) {
                arrWeight = arrWeight.slice(0, arrValue.length)
            } else if (arrWeight.length < arrValue.length) {
                let diff = arrValue.length - arrWeight.length
                for (let i = 0; i < diff; i++) {
                    arrWeight.push(0)
                }
            }
        }
        let tempWeight = JSON.parse(JSON.stringify(arrWeight));
        let result: T[] = [];
        for (let i = 0; i < count; i++) {
            let idx = this.getIdxByWeight(tempWeight)
            tempWeight[idx] = 0;
            result.push(arrValue[idx]);
        }
        return result;
    }

    public static getArrValueWithWeight<T>(data: { array: Array<T>, weight: Array<number> }, count: number = 1): T[] {
        return this.getArrValueByWeight(data.array, data.weight, count);
    }

    /**
     * 在randomArray数组中选择count个元素索引
     */
    public static randomNewArray(randomArray: any[], count: number): number[] {
        if (randomArray.length >= count) {
            let arr: number[] = [];
            let add = 0;
            while (add < count) {
                let num = this.rangeInt(0, randomArray.length - 1);
                if (arr.indexOf(num) == -1) {
                    arr.push(num);
                    add++;
                }
            }
            return arr;
        } else {
            Loger.error("随机的数量太多了");
            return null;
        }
    }

    /**
     * 从arrIn里面随出count个元素生成新的数组
     * @param arrIn 要随机的原数组
     * @param count 抽出的数量
     * @returns 随机出来的新数组
     */
    public static randomArrayFromArray<T>(arrIn: T[], count: number) {
        if (arrIn.length < count) {
            Loger.log(`count 大于 arrIn的数量,直接返回原数组`);
            return arrIn;
        }
        const arrIdx = this.randomNewArray(arrIn, count);
        if (!arrIdx) {
            return null;
        }
        let arr: T[] = [];
        for (let i = 0; i < arrIdx.length; i++) {
            const idx = arrIdx[i];
            arr.push(arrIn[idx]);
        }
        return arr;

    }

    /**打乱数组顺序并生成一个新数组 */
    public static randomSortArray<T>(arrIn: T[]) {
        let arr = JSON.parse(JSON.stringify(arrIn));
        for (let i = 1; i < arr.length; i++) {
            const random = Math.floor(Math.random() * (i + 1));
            [arr[i], arr[random]] = [arr[random], arr[i]];
        }
        return arr;
    }
}